package implementation;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.Writer;
import java.util.Set;

import roborally.IFacade;

public class Facade implements IFacade<Board, Robot, Wall, Battery, RepairKit, SurpriseBox> {

	@Override
	public Board createBoard(long width, long height) {
		Board board = new Board(width, height);
		if (Board.isValidWidthOrHeight(width) && Board.isValidWidthOrHeight(height)) {
			return board;
		} else {
			return null;
		}
	}

	@Override
	public void merge(Board board1, Board board2) {
		board1.merge(board2);
	}

	@Override
	public Battery createBattery(double initialEnergy, int weight) {
		Battery battery = new Battery(initialEnergy, weight);
		if (Battery.isValidEnergy(initialEnergy, battery.getMAX_ENERGY())) {
			return battery;
		}
		return null;
	}

	@Override
	public void putBattery(Board board, long x, long y, Battery battery) {
		try {
			board.addBattery(x, y, battery);
		} catch (NullPointerException e) {
			System.err.println(e.getMessage());
		}
	}

	@Override
	public long getBatteryX(Battery battery) throws IllegalStateException {
		if (battery.getBoard() == null) {
			throw new IllegalStateException("This battery is not placed on a board");
		} else {
			return battery.getX();
		}
	}

	@Override
	public long getBatteryY(Battery battery) throws IllegalStateException {
		if (battery.getBoard() == null) {
			throw new IllegalStateException("This battery is not placed on a board");
		} else {
			return battery.getY();
		}
	}

	@Override
	public RepairKit createRepairKit(double repairAmount, int weight) {
		RepairKit repairkit = new RepairKit(repairAmount, weight);
		if (RepairKit.isValidEnergy(repairAmount, repairkit.getMAX_ENERGY())
				&& RepairKit.isValidWeight(weight, repairkit.getMaxWeight())) {
		return repairkit;
		} else {
			return null;
		}
	}

	@Override
	public void putRepairKit(Board board, long x, long y, RepairKit repairKit) {
		try {
			board.addItem(x, y, repairKit);
		} catch (NullPointerException e) {
			System.err.println(e.getMessage());
		}
	}

	@Override
	public long getRepairKitX(RepairKit repairKit) throws IllegalStateException {
		if (repairKit.getBoard() == null) {
			throw new IllegalStateException("This repair kit is not placed on a board");
		} else {
			return repairKit.getX();
		}
	}

	@Override
	public long getRepairKitY(RepairKit repairKit) throws IllegalStateException {
		if (repairKit.getBoard() == null) {
			throw new IllegalStateException("This repair kit is not placed on a board");
		} else {
			return repairKit.getY();
		}
	}

	@Override
	public SurpriseBox createSurpriseBox(int weight) {
		SurpriseBox surpriseBox = new SurpriseBox(weight);
		if (SurpriseBox.isValidWeight(weight, surpriseBox.getMaxWeight())) {
			return surpriseBox;			
		} else {
			return null;
		}

	}

	@Override
	public void putSurpriseBox(Board board, long x, long y,
			SurpriseBox surpriseBox) {
		try {
			board.addItem(x, y, surpriseBox);
		} catch (NullPointerException e) {
			System.err.println(e.getMessage());
		}
	}

	@Override
	public long getSurpriseBoxX(SurpriseBox surpriseBox)
			throws IllegalStateException {
		if (surpriseBox.getBoard() == null) {
			throw new IllegalStateException("This surprise box is not placed on a board");
		} else {
			return surpriseBox.getX();
		}
	}

	@Override
	public long getSurpriseBoxY(SurpriseBox surpriseBox)
			throws IllegalStateException {
		if (surpriseBox.getBoard() == null) {
			throw new IllegalStateException("This surprise box is not placed on a board");
		} else {
			return surpriseBox.getY();
		}

	}

	@Override
	public Robot createRobot(int orientation, double initialEnergy) {
		Robot robot = new Robot(orientation, initialEnergy);
		if (!Robot.isValidOrientation(robot.getOrientation()) || !Robot.isValidEnergy(initialEnergy, robot.getMAX_ENERGY())) {
			return null;
		} else {
			return robot;
		}
	}

	@Override
	public void putRobot(Board board, long x, long y, Robot robot) {
		try {
		board.addRobot(x, y, robot);
		} catch (NullPointerException e) {
			System.err.println(e.getMessage());
		}
	}

	@Override
	public long getRobotX(Robot robot) throws IllegalStateException {
		if (robot.getBoard() == null) {
			throw new IllegalStateException("This robot is not placed on a board");
		} else {
		return robot.getX();
		}
	}

	@Override
	public long getRobotY(Robot robot) throws IllegalStateException {
		if (robot.getBoard() == null) {
			throw new IllegalStateException("This robot is not placed on a board");
		} else {
		return robot.getY();
		}
	}

	@Override
	public int getOrientation(Robot robot) {
		return robot.getOrientation();
	}

	@Override
	public double getEnergy(Robot robot) {
		return robot.getEnergy();
	}

	@Override
	public void move(Robot robot) {
		if (Robot.hasEnergyToMove(robot.getEnergy(), robot.get_ENERGYREQUIREDTOMOVE()))
		{
			try {
				robot.move();
			} catch (InvalidLocationException exc) {
				System.err.println(exc.getMessage());
			}
		}
	}

	@Override
	public void turn(Robot robot) {
		if (Robot.hasEnergyToTurn(robot.getEnergy(), robot.get_ENERGYREQUIREDTOTURN()))
		robot.turnClockwise();
	}

	@Override
	public void pickUpBattery(Robot robot, Battery battery) {
		robot.pickUp(battery);
	}

	@Override
	public void useBattery(Robot robot, Battery battery) {
		robot.use(battery);
	}

	@Override
	public void dropBattery(Robot robot, Battery battery) {
		robot.drop(battery);
	}

	@Override
	public void pickUpRepairKit(Robot robot, RepairKit repairKit) {
		robot.pickUp(repairKit);
	}

	@Override
	public void useRepairKit(Robot robot, RepairKit repairKit) {
		robot.use(repairKit);
	}

	@Override
	public void dropRepairKit(Robot robot, RepairKit repairKit) {
		robot.drop(repairKit);
	}

	@Override
	public void pickUpSurpriseBox(Robot robot, SurpriseBox surpriseBox) {
		robot.pickUp(surpriseBox);
	}

	@Override
	public void useSurpriseBox(Robot robot, SurpriseBox surpriseBox) {
		robot.use(surpriseBox);
	}

	@Override
	public void dropSurpriseBox(Robot robot, SurpriseBox surpriseBox) {
		robot.drop(surpriseBox);
	}

	@Override
	public void transferItems(Robot from, Robot to) {
		to.transferFrom(from);
	}

	@Override
	public int isMinimalCostToReach17Plus() {
		return 1;
	}

	@Override
	public double getMinimalCostToReach(Robot robot, long x, long y) {
		try {
		return robot.getImprovedEnergyToReach(x, y);
		} catch (OutOfMemoryError e) {
			System.err.println(e.getMessage());
		}
		return -1;
		}

	@Override
	public int isMoveNextTo18Plus() {
		return 1;
	}

	@Override
	public void moveNextTo(Robot robot, Robot other) {
		try {
		robot.moveNextTo(other);
		} catch (NullPointerException nPE) {
			System.err.println(nPE.getMessage());
		} catch (IllegalArgumentException iAE) {
			System.err.println(iAE.getMessage());
		} catch (OutOfMemoryError e) {
			System.err.println(e.getMessage());
		}
	}

	@Override
	public void shoot(Robot robot) {
		if (Robot.hasEnergyToShoot(robot.getEnergy(), robot.get_ENERGYREQUIREDTOSHOOT())) {
			robot.shoot();
		}
		
	}

	@Override
	public Wall createWall() {
		Wall wall = new Wall();
		return wall;
	}

	@Override
	public void putWall(Board board, long x, long y, Wall wall) {
		board.addWall(x, y, wall);
	}

	@Override
	public long getWallX(Wall wall) throws IllegalStateException {
		if (wall.getLocation() == null) {
			throw new IllegalStateException();
		}
		else {
		return wall.getX();
		}
	}

	@Override
	public long getWallY(Wall wall) throws IllegalStateException {
		if (wall.getLocation() == null) {
			throw new IllegalStateException();
		}
		else {
		return wall.getY();
		}
	}

	@Override
	public Set<Robot> getRobots(Board board) {
		return board.getRobots();
	}

	@Override
	public Set<Wall> getWalls(Board board) {
		return board.getWalls();
	}

	@Override
	public Set<RepairKit> getRepairKits(Board board) {
		return board.getRepairKits();
	}

	@Override
	public Set<SurpriseBox> getSurpriseBoxes(Board board) {
		return board.getSurpriseBoxes();
	}

	@Override
	public Set<Battery> getBatteries(Board board) {
		return board.getBatteries();
	}

	@Override
	public int loadProgramFromFile(Robot robot, String path) {
		try {
			robot.getProgram().loadProgram(path);
		} catch (FileNotFoundException e) {
			System.err.println(e.getMessage());
			return -1;
		} catch (IOException e) {
			System.err.println(e.getMessage());
			return -1;
		}
		return 0;
	}

	@Override
	public int saveProgramToFile(Robot robot, String path) {
		try {
			robot.getProgram().saveProgram(path);
		} catch (IOException e) {
			System.err.println(e.getMessage());
			return -1;
		}
		return 0;
	}

	@Override
	public void prettyPrintProgram(Robot robot, Writer writer) {
		try {
			writer.write(robot.getProgram().getInstructions());
		} catch (IOException e) {
			System.err.println(e.getMessage());
		}
	}

	@Override
	public void stepn(Robot robot, int n) {
		while (n>0){
			robot.getProgram().runner();
			n--;
		}
	}

}
